/**
 * promise规范
 * es是js的规范，js是es的实现 js中的原生promise 是对promise/A+规范的实现 promise的规范不止promise/A+规范
 * js中promise的then是微任务，是因为浏览器引擎是用微任务实现的，规范中之规定了是异步任务即可
 * 
 *  *let promise = new Promise((reslove, reject) => {})
 * （1）基本形态 创建传入函数，函数的参数是两个函数，外部可以用型参来调用类内部的函数
 * （2）状态管理函数 resolve() reject(), 修改实例的状态
 * （3）监听状态改变的函数 then, catch， then(f1, f2)参数必须是函数
 * （4）then是链式调用的
 * （5）all race
 * 
 * 属性
 * promiseStatus = myPromise.PENDING; //状态
 * promiseResult = null; //结果
 * onFulfilledCallbacks = []; //成功回调
 * onRejectedCallbacks = []; //失败回调
 * 
 * 方法
 * ✅resolve(result) 修改状态为成功 执行成功回调
 * ✅reject(reason) 修改状态为失败 执行失败回调
 * ✅then(onResolved, onRejected) 监听状态改变 执行成功或失败回调
 * ✅catch(onRejected) 监听状态改变 执行失败回调
 * ✅finally(callback) 监听状态改变 执行成功或失败回调
 * ✅all(paramsArr) 等待所有promise都成功 返回一个promise
 * ✅race(paramsArr) 等待第一个promise成功或失败 返回一个promise
 */
class myPromise {
  static PENDING = 'pending';
  static FULFILLED = 'fulfilled';
  static REJECTED = 'rejected';

  constructor(func) {
    this.promiseStatus = myPromise.PENDING;
    this.promiseResult = null;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    try {
      //reslove是在实例外部调用，会使this丢失，用bind绑定this为实例中的this
      func(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }
  /**
   * resolve做了哪些
   * （1）修改状态为成功
   * （2）设置结果
   * （3）执行成功回调/then中收集的回调函数
   * @param {*} result 
   */
  resolve(result) {
    setTimeout(() => {
      if (this.promiseStatus === myPromise.PENDING) {
        this.promiseStatus = myPromise.FULFILLED;
        this.promiseResult = result;
        this.onFulfilledCallbacks.forEach(callback => callback(result)); //执行then中收集的回调函数
      }
    });
  }

  /**
   * reject做了哪些事情
   * （1）修改状态为失败
   * （2）设置结果
   * （3）执行失败回调中收集的回调函数
   * @param {*} reason 
   */
  reject(reason) {
    setTimeout(() => {
      if (this.promiseStatus === myPromise.PENDING) {
        this.promiseStatus = myPromise.REJECTED;
        this.promiseResult = reason;
        this.onRejectedCallbacks.forEach(callback => callback(reason));
      }
    });
  }
  /**
   * 静态resolve方法
   * 如果传入 Promise.resolve 的值已经是一个 Promise 对象，则直接返回该 Promise 对象
   * 如果传入的是普通值（包括对象、数组、null等），则将其包装成一个已完成状态的 Promise 对象
   * 确保 Promise.resolve 总是返回一个 Promise
   * @param {*} value
   * @returns
   */
  static resolve(value) {
    if (value instanceof myPromise) {
      return value;
    }
    return new myPromise((resolve,_) => resolve(value));
  }

  /**
   * 静态reject方法
   * @param {*} reason
   * @returns
   */
  static reject(reason) {
    return new myPromise((_, reject) => reject(reason));
  }
  /**
   * 返回promise 可以链式调用
   * 根据状态来执行，处理不同的状态
   * 回调函数执行返回的值需要resolvePromise来处理
   * @param {*} onResolved
   * @param {*} onRejected
   * @returns
   */
  then(onResolved, onRejected) {
    let promise = new myPromise((resolve, reject) => {
      const handleFulfilled = () => {
        setTimeout(() => {
          try {
            if (typeof onResolved === 'function') {
              const res = onResolved(this.promiseResult);
              resolvePromise(promise, res, resolve, reject);
            } else {
              resolve(this.promiseResult);
            }
          } catch (error) {
            reject(error);
          }
        });
      };
      const handleRejected = () => {
        setTimeout(() => {
          try {
            if (typeof onRejected === 'function') {
              const res = onRejected(this.promiseResult);
              resolvePromise(promise, res, resolve, reject);
            } else {
              reject(this.promiseResult);
            }
          } catch (error) {
            reject(error);
          }
        });
      };
      if (this.promiseStatus === myPromise.PENDING) {
        this.onFulfilledCallbacks.push(handleFulfilled);
        this.onRejectedCallbacks.push(handleRejected);
      }
      if (this.promiseStatus === myPromise.FULFILLED) {
        handleFulfilled();
      }
      if (this.promiseStatus === myPromise.REJECTED) {
        handleRejected();
      }
    });
    return promise;
  }

  /**
   * catch方法，用于捕获错误
   * 实际上是then方法的语法糖
   * @param {*} onRejected
   * @returns
   */
  catch(onRejected) {
    return this.then(undefined, onRejected);
  }

  /**
   * finally方法，无论成功或失败都会执行
   * this.then() 成功的继续成功 失败的继续失败
   * reolve保证callback的返回值也能被处理
   * @param {*} callback
   * @returns
   */
  finally(callback) {
    const onResolved = value => {
      return myPromise.resolve(callback()).then(() => value);
    };
    const onRejected = reason => {
      return myPromise.resolve(callback()).then(() => {
        throw reason;
      });
    };
    return this.then(onResolved, onRejected);
  }

  /**
   * 静态all方法，等待所有promise都成功
   * @param {*} paramsArr
   * @returns promise
   */
  static all(paramsArr) {
    if (!Array.isArray(paramsArr)) {
      return myPromise.reject(new TypeError('参数必须是数组'));
    }

    if (paramsArr.length === 0) {
      return myPromise.resolve([]);
    }

    const result = [];
    let count = 0;
    return new myPromise((resolve, reject) => {
      paramsArr.forEach((item, index) => {
        /**
         * 注意处理 参数不是promise的情况
         */
        myPromise.resolve(item).then(
          res => {
            count++;
            result[index] = res;
            count === paramsArr.length && resolve(result);
          },
          err => {
            reject(err);
          }
        );
      });
    });
  }

  /**
   * 静态race方法，等待第一个promise成功或失败
   * @param {*} paramsArr
   * @returns
   */
  static race(paramsArr) {
    if (!Array.isArray(paramsArr)) {
      return myPromise.reject(new TypeError('参数必须是数组'));
    }

    if (paramsArr.length === 0) {
      return new myPromise(() => {}); // 永远处于pending状态
    }

    return new myPromise((resolve, reject) => {
      paramsArr.forEach(item => {
        myPromise.resolve(item).then(resolve, reject);
      });
    });
  }
}

//处理promise链式
  /**
   * x值的处理
   * （1）x是基本类型
   * （2）是自定义的promise对象
   * （3）是promise实例
   */
  /**
   * then结果返回值处理函数，处理回调函数是promise的情况
   * 递归查找then的链
   * @param {*} promise then的返回值promise
   * @param {*} x then回调函数的返回值
   * @param {*} resolve 对x的处理函数 then的返回值promise中的
   * @param {*} reject 对x的处理函数 then的返回值promise中的
   * @returns 
   */
function resolvePromise(promise, x, resolve, reject) {
    if (x === promise) {
      return reject(new TypeError('chaining cycle detected for promise'));
    }
    if (x instanceof myPromise) {
      x.then(res => {
        resolvePromise(promise, res, resolve, reject);
      }, reject);
    } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
      try {
        // 有then属性的对象 或者其他规范的promise，获取then属性，
        // get操作可能会有异常
        var then = x.then;
      } catch (error) {
        return reject(error);
      }
      // then应该是个可执行函数
      if (typeof then === 'function') {
        // 添加一个锁，只执行一次
        let called = false;
        try {
          then.call( //执行
            x,
            res => {
              if (called) return;
              called = true;
              resolvePromise(promise, res, resolve, reject);
            },
            rej => {
              if (called) return;
              called = true;
              reject(rej);
            }
          );
        } catch (error) {
          if (called) return;
          called = true;
          reject(error);
        }
      } else {
        resolve(x);
      }
    } else {
      resolve(x);
    }
  }

// // 测试执行
console.log('同步执行',1)
// 创建实例
const p = new myPromise((res, rej) => {
  console.log('同步执行',2)
  setTimeout(() => {
    res('ok');
    console.log('同步执行？');
  });
  // throw new Error('直接抛出异常')
});
const p2 = new myPromise((res,rej) => {
  res('last val')
})
//链式调用
const res = p.then(
  (value) => {
    console.log('异步执行',1)
    console.log('okkk',value);
    return 'okk2,'+ value
  },
  (reason) => {
    console.log('err',reason);
    return 'err2,'+ reason
  }
).then(
  res =>{
    return p2
  }
)
console.log('同步执行',3)
console.log('res',res)

// 测试静态方法
// function test() {
//   return new myPromise(resolve => {
//     setTimeout(() => {
//       console.log('test');
//       resolve('resolve的test');
//     }, 2000);
//   });
// }
// function test1() {
//   return new myPromise(resolve => {
//     setTimeout(() => {
//       console.log('test1');
//       resolve('resolve的test1');
//     }, 2000);
//   });
// }
// function test2() {
//   return new myPromise(resolve => {
//     setTimeout(() => {
//       console.log('test2');
//       resolve('resolve的test2');
//     }, 2000);
//   });
// }
// function call() {
//   myPromise.all([test(), test1(), test2()]).then(values => {
//     console.log(values);
//   });

//   myPromise.race([test(), test1(), test2()]).then(values => {
//     console.log(values);
//   });
// }
// call();

/**
 * !! 注意
 * （1）直接抛出异常，应该被reject处理
 * （2）then中的参数，不是函数也可以处理
 * （3）then本身要进行异步处理,resolve, reject也是
 * （4）实例化的时候要异步处理
 * （5）用数组保留待执行回调函数 避免 then() 比resolve（）先执行，所以要根据状态判断
 *    then中的函数执行取决于状态
 * （6）resolve reject 需要遍历执行 回调数组里的待执行函数
 * 
 */
/**
 * ? tips：
 * 静态方法：(1) static XXX = xx; (2) 类直接调用： myPromise.XXX
 * 
 * 构造函数中定义的this是实例上的属性
 * 
 * setTimeout(event,delay)宏任务 将事件放到了事件循环末尾，下次事件循环开始时执行，不是到时立即执行 
 * 
 * new myclass(fn(f1,f2) => {
 *  f1(); //要注意this的指向
 *  ...
 * })
 */
 
/**
 * promise相关
 * 
 * 【JS手写系列】手写实现Promise https://juejin.cn/post/7194266882088648761?searchId=20240123112749B108C7FA05ACF75B38D5#heading-21
 * Promise/A+ 规范 https://promisesaplus.com/
 * 参考 Promise/A+ 规范和测试用例手写 Promise https://juejin.cn/post/7205549412352376892
 * V8 Promise源码全面解读 https://juejin.cn/post/7055202073511460895
 */
